package com.hcc.flow.server.common.utils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.expression.ParseException;

import com.hcc.flow.server.common.constant.Constant;
import com.hcc.flow.server.common.constant.ParamConfig;
import com.hcc.flow.server.common.constant.WeChatConfig;

/**
 * The Class CommUtil.
 */
public class CommUtil {
	protected static final Log log = LogFactory.getLog(CommUtil.class);

	/**
	 * Instantiates a new comm util.
	 */
	private CommUtil() {
	}

	public static double add(Object a, Object b) {
		double ret = 0.0;
		BigDecimal e = new BigDecimal(CommUtil.null2Double(a));
		BigDecimal f = new BigDecimal(CommUtil.null2Double(b));
		ret = e.add(f).doubleValue();
		DecimalFormat df = new DecimalFormat("0.00");
		df.setRoundingMode(RoundingMode.HALF_UP);
		return Double.valueOf(df.format(ret));
	}

	/**
	 * Null2 int.
	 *
	 * @param s
	 *            the s
	 * @return the int
	 */
	public static int null2Int(Object s) {
		int v = 0;
		if (s != null)
			try {
				String str = s.toString();
				if(str.indexOf(".") > 0 && isNumber(str))
					v = CommUtil.null2Int(Double.valueOf(str).intValue());
				else
					v = Integer.parseInt(s.toString());
			} catch (Exception e) {
			}
		return v;
	}

	/**
	 * Parses the date.
	 *
	 * @param type
	 *            the type
	 * @param date
	 *            the date
	 * @return the int
	 */
	public static int parseDate(String type, Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		if (type.equals("y")) {
			return cal.get(Calendar.YEAR);
		}
		if (type.equals("M")) {
			return cal.get(Calendar.MONTH) + 1;
		}
		if (type.equals("d")) {
			return cal.get(Calendar.DAY_OF_MONTH);
		}
		if (type.equals("H")) {
			return cal.get(Calendar.HOUR_OF_DAY);
		}
		if (type.equals("m")) {
			return cal.get(Calendar.MINUTE);
		}
		if (type.equals("s")) {
			return cal.get(Calendar.SECOND);
		}
		return 0;
	}

	/**
	 * Format date.
	 *
	 * @param s
	 *            the s
	 * @param format
	 *            the format
	 * @return the java.util. date
	 */
	public static java.util.Date formatDate(String s, String format) {
		java.util.Date d = null;
		try {
			SimpleDateFormat dFormat = new java.text.SimpleDateFormat(format);
			d = dFormat.parse(s);
		} catch (Exception e) {
		}
		return d;
	}

	/**
	 * Format time.
	 *
	 * @param format
	 *            the format
	 * @param v
	 *            the v
	 * @return the string
	 */
	public static String formatTime(String format, Object v) {
		if (v == null)
			return null;
		if (v.equals(""))
			return "";
		SimpleDateFormat df = new SimpleDateFormat(format);
		return df.format(v);
	}

	public static String formatTimeAddPrefix(String format, Object v,String prefix) {
		String formatTime = formatTime(format, v);
		if (formatTime == null)
			return null;
		if (formatTime.equals(""))
			return "";
		if(prefix == null){
			prefix = Constant.DATE_TO_DAY_REMARKS;
		}
		return prefix + formatTime;
	}
	
	
	public static String dateCheck(Date time,Date now) {
		//return null;
		
		if(time == null){
			return null;
		}
		if(now == null){
			now = new Date();
		}
		return DateUtils.isSameDay(now,time)?CommUtil.formatTimeAddPrefix("HH:mm:ss",time,null):CommUtil.formatShortDate(time);
	}
	
	/**
	 * Format long date.
	 *
	 * @param v
	 *            the v
	 * @return the string
	 */
	public static String formatLongDate(Object v) {
		if (v == null || v.equals(""))
			return "";
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		return df.format(v);
	}

	/**
	 * Format short date.
	 *
	 * @param v
	 *            the v
	 * @return the string
	 */
	public static String formatShortDate(Object v) {
		if (v == null)
			return null;
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		return df.format(v);
	}
	
	public static String formatShortDateX(Object v) {
		if (v == null)
			return null;
		SimpleDateFormat df = new SimpleDateFormat("yyyy/MM/dd");
		return df.format(v);
	}

	/**
	 * 通过时间秒毫秒数判断两个时间的间隔天数
	 * 
	 * @param date1
	 * @param date2
	 * @return
	 */
	public static int differentDaysByMillisecond(Date date1, Date date2) {
		int days = (int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24));
		log.debug(Math.ceil(((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24.0))));
		return days;
	}
	/**
	 * 两个日期相差值
	 * 
	 * @param date1
	 * @param date2
	 * @return
	 */
	public static Long DateUntil(Date date1, Date date2,ChronoUnit chronoUnit) {
		if(date1 != null && date2 != null){
			LocalDate startDate=LocalDateTime.ofInstant(date1.toInstant(), ZoneId.systemDefault()).toLocalDate();
			LocalDate endDate=LocalDateTime.ofInstant(date2.toInstant(), ZoneId.systemDefault()).toLocalDate();
			if(chronoUnit == null){
				chronoUnit = ChronoUnit.DAYS;
			}
			if(chronoUnit.equals(ChronoUnit.DAYS)){
				return startDate.until(endDate, chronoUnit)+1;
			}
			return startDate.until(endDate, chronoUnit);
        }
		return null;
	}
	/**
	 * 两个时间相差值
	 * 
	 * @param date1
	 * @param date2
	 * @return
	 */
	public static Long DateTimeUntil(Date date1, Date date2,ChronoUnit chronoUnit) {
		if(date1 != null && date2 != null){
			LocalDateTime startDate = LocalDateTime.ofInstant(date1.toInstant(), ZoneId.systemDefault());
			LocalDateTime endDate=LocalDateTime.ofInstant(date2.toInstant(), ZoneId.systemDefault());
			if(chronoUnit == null){
				chronoUnit = ChronoUnit.DAYS;
			}
			return startDate.until(endDate, chronoUnit);
        }
		return null;
	}
	/** 
     * 两个时间相差距离多少天多少小时多少分多少秒 
     * @return String 返回值为：xx天xx小时xx分xx秒 
     */  
    public static String getDistanceTime(Date one,Date two,String accurate) {  
        long day = 0;  
        long hour = 0;  
        long min = 0;  
        long sec = 0;  
        try {  
            long time1 = one.getTime();  
            long time2 = two.getTime();  
            long diff ;  
            if(time1<time2) {  
                diff = time2 - time1;  
            } else {  
            	return "已过期";  
            }  
            day = diff / (24 * 60 * 60 * 1000);  
            if("H".equals(accurate) || "M".equals(accurate) || "S".equals(accurate)){
            	hour = (diff / (60 * 60 * 1000) - day * 24); 
            }
            if("M".equals(accurate) || "S".equals(accurate)){
            	min = ((diff / (60 * 1000)) - day * 24 * 60 - hour * 60);  
            }
            if("S".equals(accurate)){
            	sec = (diff/1000-day*24*60*60-hour*60*60-min*60);  
            }
        } catch (ParseException e) {
        	return "未知";  
        }
        StringBuffer lsTime = new StringBuffer();
        if(day > 0){
        	lsTime.append(day + "天");
        }
        if((("H".equals(accurate) || "M".equals(accurate) || "S".equals(accurate)) && hour > 0) || lsTime.length() == 0){
        	lsTime.append(hour + "小时");
        }
        if((("M".equals(accurate) || "S".equals(accurate)) && min > 0) || lsTime.length() == 0){
        	lsTime.append(min + "分");
        }
        if(("S".equals(accurate) && sec > 0) || lsTime.length() == 0){
        	lsTime.append(sec + "秒");
        }
        return  lsTime.toString();  
    }
	// 获得某天最大时间 2018-03-20 23:59:59
	public static Date getEndOfDay(Date date) {
		if(date == null){
			return null;
		}
		Calendar calendarEnd = Calendar.getInstance();
		calendarEnd.setTime(date);
		calendarEnd.set(Calendar.HOUR_OF_DAY, 23);
		calendarEnd.set(Calendar.MINUTE, 59);
		calendarEnd.set(Calendar.SECOND, 59);
		// 防止mysql自动加一秒,毫秒设为0
		calendarEnd.set(Calendar.MILLISECOND, 0);
		return calendarEnd.getTime();

	}

	// 获得某天最小时间 2018-03-20 00:00:00
	public static Date getStartOfDay(Date date) {
		if(date == null){
			return null;
		}
		LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()),
				ZoneId.systemDefault());
		LocalDateTime startOfDay = localDateTime.with(LocalTime.MIN);
		return Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant());

	}
	// 日期加减
	public static Date getDateJJ(Date date,Integer day) {
		Calendar calendarEnd = Calendar.getInstance();
		calendarEnd.setTime(date);
		calendarEnd.add(Calendar.DATE, day);
		return calendarEnd.getTime();
	}
	// 日期秒数加减
	public static Date getDateJJSecond(Date date,Integer second) {
		Calendar calendarEnd = Calendar.getInstance();
		calendarEnd.setTime(date);
		calendarEnd.add(Calendar.SECOND, second);
		return calendarEnd.getTime();
	}
	public static String imgAllUrl(String img) {
		if(StringUtilsV2.isBlank(img)){
			return null;
		}
		if(StringUtilsV2.isNotBlank(img) && !img.startsWith("http") && !img.startsWith("/tourapi/")){
			img = ParamConfig.filePath + img;
		}
		return img;
	}
	/**
	 * Null2 float.
	 *
	 * @param s
	 *            the s
	 * @return the float
	 */
	public static float null2Float(Object s) {
		float v = 0.0f;
		if (s != null)
			try {
				v = Float.parseFloat(s.toString());
			} catch (Exception e) {
			}
		return v;
	}

	/**
	 * Null2 double.
	 *
	 * @param s
	 *            the s
	 * @return the double
	 */
	public static double null2Double(Object s) {
		double v = 0.0;
		if (s != null)
			try {
				v = Double.parseDouble(null2String(s));
			} catch (Exception e) {
		}
		return v;
	}

	/**
	 * Null2 boolean.
	 *
	 * @param s
	 *            the s
	 * @return true, if successful
	 */
	public static boolean null2Boolean(Object s) {
		boolean v = false;
		if (s != null)
			try {
				v = Boolean.parseBoolean(s.toString());
			} catch (Exception e) {
		}
		return v;
	}

	/**
	 * Null2 string.
	 *
	 * @param s
	 *            the s
	 * @return the string
	 */
	public static String null2String(Object s) {
		return s == null ? "" : s.toString().trim();
	}

	/**
	 * Null2 long.
	 *
	 * @param s
	 *            the s
	 * @return the long
	 */
	public static Long null2Long(Object s) {
		Long v = -1l;
		if (s != null)
			try {
				if (s instanceof Double)
					v = Math.round((double) s);
				else
					v = Long.parseLong(s.toString());
			} catch (Exception e) {
		}else{
			return null;
		}
		return v;
	}

	/**
	 * Null2 big decimal.
	 *
	 * @param s
	 *            the s
	 * @return the big decimal
	 */
	public static BigDecimal null2BigDecimal(Object s) {
		BigDecimal v = new BigDecimal("0");
		if (s != null) {
			try {
				v = new BigDecimal(null2String(s));
			} catch (Exception e) {
			}
		}else{
			return null;
		}
		return v;
	}
	/**
	 * 是否是整数
	 * @param str
	 * @return
	 */
	public static boolean isNumeric(String str){
		if(StringUtilsV2.isBlank(str)){
			return false;
		}
	    Pattern pattern = Pattern.compile("[0-9]*");
	    return pattern.matcher(str).matches();
	}  
	/**
	 * 是否是手机号
	 * 
	 * @param mobiles
	 * @return
	 */
	public static boolean isMobileNO(String mobiles) {
		if (StringUtilsV2.isNotBlank(mobiles) && mobiles.length() == 11) {
			String mobile = "^(1[3-9][0-9])\\d{8}$";
			Pattern p = Pattern.compile(mobile);
			Matcher m = p.matcher(mobiles);
			return m.matches();
		} else {
			return false;
		}
	}
	// 手机号码前三后四脱敏
    public static String mobileEncrypt(String mobile) {
        if (StringUtilsV2.isEmpty(mobile) || (mobile.length() != 11)) {
            return mobile;
        }
        return mobile.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
    }
	/**
	 * 获取某个超链接中的参数值
	 * 
	 * @param url
	 * @param name
	 * @return
	 */
	public static String getUrlParam(String url, String name) {
		String urlzz = "(^|\\?|&)" + name + "=([^&]*)(&|$)";
		Pattern p = Pattern.compile(urlzz);
		Matcher m = p.matcher(url);
		while (m.find()) {
			return m.group();
		}
		return null;
	}

	/**
	 * 生成UUID(没有中划线)
	 * 
	 * @return UUID(没有中划线)
	 */
	public static String uuid() {
		return UUID.randomUUID().toString().replace("-", "");
	}

	/**
	 * 指定字符串出现的次数
	 */
	public static int numberOfOccurrences(String st,String M) {
		if(st == null || M == null){
			return 0;
		}
		return (st.length()-st.replaceAll(M, "").length())/M.length();
	}
	  //截取数字  
	public static String getNumbers(String content) {
		if(StringUtilsV2.isBlank(content)){
			return null;
		}
		return content.replaceAll("[^\\d.]+","");
	}
	/**
	 * 是否是数字（包括浮点）
	 * @param str
	 * @return
	 */
	public static boolean isNumber(String str){
		if(StringUtilsV2.isBlank(str)){
			return false;
		}
		String reg = "^[0-9]+(.[0-9]+)?$";
		return str.matches(reg);
	}
	/*public static void main(String[] args) {
		Double dsize = Math.floor(43200 / 100000);
		System.out.println(dsize);
		Calendar calendarEnd = Calendar.getInstance();
		calendarEnd.setTime(new Date());
		calendarEnd.add(Calendar.DATE, -7);
		calendarEnd.add(Calendar.HOUR, 1);
		calendarEnd.add(Calendar.MINUTE, 1);
		calendarEnd.add(Calendar.SECOND, 1);
		calendarEnd.getTime();
	
		log.debug(CommUtil.formatLongDate(calendarEnd.getTime()));
		
		log.debug(CommUtil.formatLongDate(new Date()));
		//log.debug(CommUtil.formatLongDate(CommUtil.getDateJJ(new Date(), -7)));
		log.debug(CommUtil.DateUntil(calendarEnd.getTime(), new Date(), null));
		log.debug(CommUtil.DateTimeUntil(calendarEnd.getTime(), new Date(), null));
		log.debug(CommUtil.getDistanceTime(calendarEnd.getTime(), new Date(),"M"));
		//way2("acacss11asaa","a");
	}*/
	
	public static <T> List<T> getDuplicateElements(List<T> list) {
        return list.stream()
                .collect(Collectors.toMap(e -> e, e -> 1, (a, b) -> a + b)) // 获得元素出现频率的 Map，键为元素，值为元素出现的次数
                .entrySet().stream() // Set<Entry>转换为Stream<Entry>
                .filter(entry -> entry.getValue() > 1) // 过滤出元素出现次数大于 1 的 entry
                .map(entry -> entry.getKey()) // 获得 entry 的键（重复元素）对应的 Stream
                .collect(Collectors.toList()); // 转化为 List
    }

	public static void main(String[] args) {
		
		boolean  aa = true;
		if(aa) {
			System.out.println(CommUtil.null2Int("15.22"));
			System.out.println(CommUtil.null2Int(Double.valueOf("15.22").intValue()));
			String s = "11a1.00000";
			if(s.indexOf(".") > 0){
				  //正则表达
				  s = s.replaceAll("0+?$", "");//去掉后面无用的零
				  System.out.println(s);
				  s = "11a1.00100";
				  s = s.replaceAll("[.]$", "");//如小数点后面全是零则去掉小数点
				  System.out.println(s);
			}
			
			List<Long> ls = null;
			
			System.out.println(StringUtilsV2.join(ls,","));
			
	        List<String> list1 = new ArrayList<String>();
	        list1.add("1111");
	        list1.add("2222");
	        list1.add("3333");
	
	        List<String> list2 = new ArrayList<String>();
	        list2.add("3333");
	        list2.add("4444");
	        list2.add("5555");
	
	        // 交集
	        List<String> intersection = list1.stream().filter(item -> list2.contains(item)).collect(Collectors.toList());
	        System.out.println("---得到交集 intersection---");
	        intersection.parallelStream().forEach(System.out :: println);
	
	        // 差集 (list1 - list2)
	        List<String> reduce1 = list1.stream().filter(item -> !list2.contains(item)).collect(Collectors.toList());
	        System.out.println("---得到差集 reduce1 (list1 - list2)---");
	        reduce1.parallelStream().forEach(System.out :: println);
	
	        // 差集 (list2 - list1)
	        List<String> reduce2 = list2.stream().filter(item -> !list1.contains(item)).collect(Collectors.toList());
	        System.out.println("---得到差集 reduce2 (list2 - list1)---");
	        reduce2.parallelStream().forEach(System.out :: println);
	
	        // 并集
	        List<String> listAll = list1.parallelStream().collect(Collectors.toList());
	        List<String> listAll2 = list2.parallelStream().collect(Collectors.toList());
	        listAll.addAll(listAll2);
	        System.out.println("---得到并集 listAll---");
	        listAll.parallelStream().forEach(System.out :: println);
	        //System.out.println("---得到并集 listAll---123");
	        //getDuplicateElements(listAll).parallelStream().forEach(System.out :: println);
	        // 去重并集
	        List<String> listAllDistinct = listAll.stream().distinct().collect(Collectors.toList());
	        System.out.println("---得到去重并集 listAllDistinct---");
	        listAllDistinct.parallelStream().forEach(System.out :: println);
	
	        System.out.println("---原来的List1---");
	        System.out.println("String:"+listAllDistinct.toString());
	        list1.parallelStream().forEach(System.out :: println);
	        System.out.println("---原来的List2---");
	        list2.parallelStream().forEach(System.out :: println);
	
	        // 一般有filter 操作时，不用并行流parallelStream ,如果用的话可能会导致线程安全问题
	        
	        Date d = new Date();
	        System.out.println(d.getTime());
	
	        String a = "2进2出";
	        System.out.println(CommUtil.null2Int(getNumbers(a)));
	        
	        List<String> collectUserIds = new  ArrayList<String>();
			//collectUserIds.remove("1");
			//collectUserIds.remove(null);
			System.out.println("---1.collectUserIds---");
			collectUserIds.parallelStream().forEach(System.out :: println);
			collectUserIds = collectUserIds.stream().distinct().collect(Collectors.toList());
		
			collectUserIds.remove(null);
			System.out.println("---2.collectUserIds---");
			collectUserIds.parallelStream().forEach(System.out :: println);
			
			String b = "";
			testa(b);
			System.out.println("结束"+b);
			
			int i = 1;
			fun1(i);
	        System.out.println(i);//i = 1
	        StringBuffer ss = new StringBuffer("main");

	        System.out.println(ss.toString());//main

	        fun2(ss);

	        System.out.println(ss+"aa");//mainfun2

	        fun3(ss);

	        System.out.println(ss.toString());//mainfun2
	        
	        Date aDate = new Date();
			System.out.println(CommUtil.formatTime("yy:MM:dd-HH:mm:ss:SSS", aDate));
			System.out.println(CommUtil.formatTime("yy:MM:dd-HH:mm:ss:SSS", getDateJJSecond(aDate,1)));
			StringBuffer sb = new StringBuffer().append("123").append(456);
			System.out.println(sb);
		}
		//String sql = "insert into sys_logs(log_id,user_id, log_type, module, flag, remark, create_time) values('1c063bdcebf311e99358e0d55edb21ed', '1', 1, '登陆', true, ?, now())";
		//sql = sql.replaceFirst("\\?", "null");
		/*System.out.println(MsgType.RESULT.toString().toLowerCase());
		for (MsgTaskType m : MsgTaskType.values()) {
			System.out.println(m.getCode()+","+m.getName());
		}*/
		//String o = "重庆市hcc-flow数字技术有限公司";
		//System.out.println(o.replaceAll("(?:省|市|有限公司|重庆)", ""));
    }
	
	private static void testa(String a) {
		a += "123456";
	}
	
	//基本类型的参数传递
    public static void fun1(int m){
        m = 100;
    }

    //参数为对象，不改变引用的值
    public static void fun2(StringBuffer s){
    	s.setLength(0);
        s.append("fun2");
    }

    //参数为对象，改变引用的值
    public static void fun3(StringBuffer s){
        s = new StringBuffer("fun3");
    }
    
    /**
    *phone :手机号-座机
    *return : true or false
    */
    public static boolean isMobile(String phone){
    	Pattern p1 = null;
    	Pattern p2 = null;
    	Pattern p3 = null;
    	Matcher m = null;
    	boolean result = false;
    	p1 = Pattern .compile("^(1[3-9][0-9])\\d{8}$");//手机号
    	p2 = Pattern .compile("^[0][1-9]{2,3}-[0-9]{5,10}$");//带区号验证
    	p3 = Pattern .compile("^[1-9]{1}[0-9]{5,8}$");//没有区号的验证
    	if(phone.length() == 11){
    		m = p1.matcher(phone);
    		result = m.matches();
    	}else if(phone.length() > 9){
    		m = p2.matcher(phone);
    		result = m.matches();
    	}else{
    		m = p3.matcher(phone);
    		result = m.matches();
    	}
    	return result;
    }
    
    public static String icon(String icon) {
		if(StringUtilsV2.isBlank(icon)){
			return null;
		}
		if(StringUtilsV2.isNotBlank(icon) && !icon.startsWith(WeChatConfig.herfSuffix) && !icon.startsWith("http")){
			icon = WeChatConfig.herfSuffix + icon;
		}
		return icon;
	}
    
    /*public static ApiResult<?> checkId(List<String> notIds,String checkId) {
    	//非administrator账户
		if(!"1".equals(UserUtil.getLoginUser().getUserId()) && notIds.contains(checkId)){
			return ApiResult.error("该数据为系统数据，不允许操作");
		}
		return ApiResult.ok();
	}*/
}
